package org.extremengine.common;

import java.util.HashSet;
import java.util.Set;

import org.extremengine.shape.ParallelRectangle;
import org.extremengine.shape.Shape;

/**
 * 刚体对象
 * 
 * @author yuxing
 * 
 */
public class RigidBody implements Collidable {

	protected String name;

	// if false, no collision will cause this rigid body move, but set velocity on rigid body will move it.
	protected boolean isMovable = true;

	protected double friction;

	protected double elasticity = 0.5;

	protected int mass = 0;

	protected Velocity v = new Velocity(0, 0);

	protected Shape shape;

	protected ParallelRectangle aabb;
	
	protected Set<Collidable> stickyMatters = new HashSet<Collidable>();

	public RigidBody(double friction, double elasticity, int mass, Shape shape) {
		super();
		this.friction = friction;
		this.mass = mass;
		this.setElasticity(elasticity);
		this.setShape(shape);
	}

	/**
	 * 按照当前速度移动给定时间内运行的距离。
	 * @param timePeirod
	 */
	public void transform(long timePeirod) {
		this.shape.transform(v, timePeirod);
	}
	
	/**
	 * 与某物体接触。
	 * @param collidable
	 */
	public void stickWith(Collidable collidable) {
		if(stickyMatters.contains(collidable) == false) {
			stickyMatters.add(collidable);
		}
	}
	
	/**
	 * 是否与另一物体接触。
	 * @param collidable
	 * @return
	 */
	public boolean isStickyWith(Collidable collidable) {
		return stickyMatters.contains(collidable);
	}
	
	/**
	 * 
	 * @param collidable
	 */
	public void unstickWith(Collidable collidable) {
		stickyMatters.remove(collidable);
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getFriction() {
		return friction;
	}

	public void setFriction(double friction) {
		this.friction = friction;
	}
	
	/**
	 * Get Shape at specific time ago, like time machine, used for position retreating.
	 * @param timeBefore
	 * @return
	 */
	public Shape getShape(long timeBefore) {
		double delta = this.v.getSpeed() * timeBefore;
		double deltax = Math.cos(Math.toRadians(this.getV().getAngleDegree() + 180)) * delta;
		double deltay = Math.sin(Math.toRadians(this.getV().getAngleDegree() + 180)) * delta;
		Shape clonedShape = this.shape.clone();
		clonedShape.transform(deltax, deltay);
		return clonedShape;
	}

	public Shape getShape() {
		return shape;
	}

	public void setShape(Shape shape) {
		this.shape = shape;
		this.aabb = ParallelRectangle.wrap(shape);
	}

	public boolean isMovable() {
		return isMovable;
	}

	public void setMovable(boolean isMovable) {
		this.isMovable = isMovable;
	}

	public double getElasticity() {
		return elasticity;
	}

	/**
	 * 设置弹性系数，范围0-1，超出则自动缩小。
	 * @param elasticity
	 */
	public void setElasticity(double elasticity) {
		if (elasticity > 1) {
			this.elasticity = 1;
		}
		else if (elasticity < 0) {
			this.elasticity = 0;
		}
		else {
			this.elasticity = elasticity;
		}
	}

	public Velocity getV() {
		return v;
	}

	public void setV(Velocity v) {
		this.v = v;
	}

	public int getMass() {
		return mass;
	}

	public void setMass(int mass) {
		this.mass = mass;
	}

	/**
	 * 获得刚体对象形状的AABB包围盒。
	 * @return
	 */
	public ParallelRectangle getAabb() {
		return aabb;
	}

	@Override
	public String toString() {
		return name + "[" + mass + "KG, " + v.getAccelx() + "ACC, " + Utils.trimAfterDecimalPoint(v.getSpeed(), 4)
				+ "M/S, " + Utils.trimAfterDecimalPoint(v.getAngleDegree()) + "Deg, " + shape.toString() + "]";
	}

}
